#ifndef _CD2d_UTIL_H_
#define _CD2d_UTIL_H_

#include "agp_data.h"
#include <fstream>
using namespace std;

///////////////////////////////////////////////////////////////////////////
// count number of vertices from s to e
inline int count_v( agp_vertex * s, agp_vertex * e ){
    int c=0;
    while( s!=e ){ c++; s=s->getNext(); }
    return c+1;
}

inline void read_poly(istream& fin, agp_poly& poly)
{
    //throw away lines that are # and empty
    int poly_number=-1; 
    do{
        string comments;
        getline(fin,comments);
        if( !comments.empty() && comments[0]!='#' )
            poly_number=atoi(comments.c_str());
    }while(poly_number<0);

    fin>>poly;
}

inline void read_poly(const string& name, agp_poly& poly)
{
    ifstream fin(name.c_str());
    if( fin.good()==false ){
        cerr<<"! ERROR: CANNOT open file : "<<name<<endl;
        return;
    }
    read_poly(fin,poly);
    //close the file
    fin.close();
}

///////////////////////////////////////////////////////////////////////////
// Save the polys as *.ply file
inline void save_poly(const string& name, agp_poly& poly)
{
    //count total polygonal chain
    ofstream fout(name.c_str());
    if( fout.good()==false ){
        cerr<<"! ERROR: CANNOT open file : "<<name<<endl;
        return;
    }
    fout<<poly;
    fout.close();
}

///////////////////////////////////////////////////////////////////////////
//compute the normal vertor to the given vertor v
inline Vector2d computeNormal(const Vector2d& v)
{
    Vector2d normal;
    if( v[0]==0 ){
        if(v[1]>0){ normal[0]=1; normal[1]=0; }
        else{ normal[0]=-1; normal[1]=0; }
    }
    else if( v[0]>0 ){
        normal[1]=-1;
        normal[0]=(v[1]/v[0]);
    }
    else{//v[0]<0
        normal[1]=1;
        normal[0]=-(v[1]/v[0]);
    }
    normal=normal.normalize();
    return normal;
}

///////////////////////////////////////////////////////////////////////////
//compute the center of the poly chain
inline Point2d polyCenter(const agp_poly& poly)
{
    Point2d com;
    int vsize=0;

    agp_vertex * head=poly.getHead();
    agp_vertex * ptr=head;
    do{
        com[0]+=ptr->getPos()[0];
        com[1]+=ptr->getPos()[1];
        vsize++;
        ptr=ptr->getNext();
    }while(ptr!=head); //end while
    com[0]/=vsize;
    com[1]/=vsize;
    return com;
}

///////////////////////////////////////////////////////////////////////////
//compute the Radius of the poly chain
inline double polyRadius(const agp_poly& poly, const Point2d& O)
{
    double R=0;
    agp_vertex * head=poly.getHead();
    agp_vertex * ptr=head;
    do{
        double d=(O-ptr->getPos()).normsqr();
        if(d>R) R=d;
        ptr=ptr->getNext();
    }while(ptr!=head); //end while
    return sqrt(R);
}

inline double polyRadius
(const agp_poly& poly, bool useOrigin=false)
{
    Point2d O(0,0);
    O=polyCenter(poly);
    return polyRadius(poly,O);
}

///////////////////////////////////////////////////////////////////////////
// Compute area of the polygon
inline double A_tri(const Point2d& p1, const Point2d& p2,const Point2d& p3)
{
    return ((p2[0]-p1[0])*(p3[1]-p1[1])-(p3[0]-p1[0])*(p2[1]-p1[1]))/2;
}

inline double A_poly(const list<agp_vertex*>& poly)
{
    typedef list<agp_vertex*>::const_iterator VIT;
    double Area=0;

    for(VIT i=poly.begin();i!=poly.end();i++){
        VIT ni=i; ni++;
        if(ni==poly.end())
            ni=poly.begin();
        Area+=A_tri(Point2d(0,0),(*i)->getPos(),(*ni)->getPos());
    }//end for
    return Area;
}

inline double A_poly(const agp_poly& poly)
{
    agp_vertex * ptr=poly.getHead();
    agp_vertex * head=ptr;
    double Area=0;
    do{
        agp_vertex * n=ptr->getNext();
        Area+=A_tri(Point2d(0,0),ptr->getPos(),n->getPos());
        ptr=n;
    }while( ptr!=head);

    //cout<<((poly.getType()==agp_poly::PIN)?"IN ":"OUT ")<<Area<<endl;
    return Area;
}

#endif //_CD2d_UTIL_H_

